package org.sunflower.t.wxpaytest.config;

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.wechat.pay.contrib.apache.httpclient.util.RsaCryptoUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.sunflower.t.wxpaytest.infrastructure.WxPayV3Properties;
import org.sunflower.t.wxpaytest.infrastructure.exception.WxPayV3Exception;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;

/**
 * @author: TanJingyu
 * @create: 2021-09-26 11:30
 **/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(value = WxPayV3Properties.class)
@RequiredArgsConstructor
@Slf4j
public class WxPayV3Configuration implements InitializingBean {
    private final WxPayV3Properties properties;

    @Bean
    public HttpClient httpClient(AutoUpdateCertificatesVerifier verifier) {
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(properties.getSecret().getMerchantId(), properties.getSecret().getMerchantSerialNumber(), loadMerchantPrivateKey())
                .withValidator(new WechatPay2Validator(verifier));

        // 定制化配置HttpClient...

        return builder.build();
    }

    @Bean
    public SecretUtil secretUtil(AutoUpdateCertificatesVerifier verifier) {
        return new SecretUtil(verifier, loadMerchantPrivateKey());
    }

    @Bean
    @Primary
    public AutoUpdateCertificatesVerifier autoUpdateCertificatesVerifier() {
        return new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(properties.getSecret().getMerchantId(),
                        new PrivateKeySigner(properties.getSecret().getMerchantSerialNumber(),
                                loadMerchantPrivateKey())),
                properties.getSecret().getApiV3Key().getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 根据配置文件信息加载商户私钥
     */
    private PrivateKey loadMerchantPrivateKey() {
        PrivateKey privateKey = null;
        String content = properties.getSecret().getPrivateKey().getContent();
        if (properties.getSecret().getPrivateKey().isFile()) {
            // 私钥存储在文件
            try {
                privateKey = PemUtil.loadPrivateKey(
                        new FileInputStream("src/main/resources/" + content));
            } catch (FileNotFoundException e) {
                log.error("加载商户私钥失败，请确认文件位置！{}", content);
                throw new WxPayV3Exception(String.format("加载商户私钥失败，请确认文件位置！%s", content));
            }
        }else {
            // 私钥为String字符串
            privateKey = PemUtil.loadPrivateKey(
                    new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));
        }

        return privateKey;
    }

    @Override
    public void afterPropertiesSet() {
        properties.correctBySelf();
    }

    public static class SecretUtil {
        private AutoUpdateCertificatesVerifier verifier;
        private PrivateKey privateKey;

        public SecretUtil(AutoUpdateCertificatesVerifier verifier, PrivateKey privateKey) {
            this.verifier = verifier;
            this.privateKey = privateKey;
        }

        public String encrypt(String text) {
            // 从Verifier中获得微信支付平台证书加密
            try {
                return RsaCryptoUtil.encryptOAEP(text, verifier.getValidCertificate());
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
                return "{}";
            }
        }

        public String decrypt(String text) {
            // 使用商户私钥解密
            try {
                return RsaCryptoUtil.decryptOAEP(text, privateKey);
            } catch (BadPaddingException e) {
                e.printStackTrace();
                return "{}";
            }
        }
    }
}
